home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / lib / python2.6 / dist-packages / pyatspi / accessible.pyc (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2009-04-20  |  21.6 KB  |  737 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (Python 2.6)
  3.  
  4. '''
  5. Creates functions at import time that are mixed into the 
  6. Accessibility.Accessible base class to make it more Pythonic.
  7.  
  8. Based on public domain code originally posted at 
  9. U{http://wwwx.cs.unc.edu/~parente/cgi-bin/RuntimeClassMixins}.
  10.  
  11. @var _ACCESSIBLE_CACHE: Pairs hash values for accessible objects to 
  12.   L{_PropertyCache} bags. We do not store actual accessibles in the dictionary
  13.   because that would +1 their ref counts and cause __del__ to never be called
  14.   which is the method we rely on to properly invalidate cache entries.
  15. @type _ACCESSIBLE_CACHE: dictionary
  16. @var _CACHE_LEVEL: Current level of caching enabled. Checked dynamically by
  17.   L{_AccessibleMixin}
  18. @type _CACHE_LEVEL: integer
  19.  
  20. @author: Peter Parente
  21. @organization: IBM Corporation
  22. @copyright: Copyright (c) 2005, 2007 IBM Corporation
  23. @license: LGPL
  24.  
  25. This library is free software; you can redistribute it and/or
  26. modify it under the terms of the GNU Library General Public
  27. License as published by the Free Software Foundation; either
  28. version 2 of the License, or (at your option) any later version.
  29.  
  30. This library is distributed in the hope that it will be useful,
  31. but WITHOUT ANY WARRANTY; without even the implied warranty of
  32. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  33. Library General Public License for more details.
  34.  
  35. You should have received a copy of the GNU Library General Public
  36. License along with this library; if not, write to the
  37. Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  38. Boston, MA 02111-1307, USA.
  39.  
  40. Portions of this code originally licensed and copyright (c) 2005, 2007
  41. IBM Corporation under the BSD license, available at
  42. U{http://www.opensource.org/licenses/bsd-license.php}
  43. '''
  44. import new
  45. import types
  46. import ORBit
  47. import Accessibility
  48. import constants
  49. import utils
  50. import registry
  51. import weakref
  52. _ACCESSIBLE_CACHE = weakref.WeakValueDictionary()
  53. _ACCESSIBLE_USER_DATA = weakref.WeakValueDictionary()
  54. _CACHE_LEVEL = None
  55.  
  56. class _PropertyCache:
  57.     
  58.     def wipe(self):
  59.         self.__dict__ = { }
  60.  
  61.  
  62.  
  63. class _UserData:
  64.     value = None
  65.  
  66.  
  67. def getCacheLevel():
  68.     '''
  69.   Gets the current level of caching.
  70.   
  71.   @return: None indicating no caching is in effect. 
  72.     L{constants.CACHE_INTERFACES} indicating all interface query results are
  73.     cached. L{constants.CACHE_PROPERTIES} indicating all basic accessible
  74.     properties are cached.
  75.   @rtype: integer
  76.   '''
  77.     return _CACHE_LEVEL
  78.  
  79.  
  80. def setCacheLevel(val):
  81.     '''
  82.   Sets the desired level of caching for all accessible objects created after
  83.   this function is invoked. Immediately clears the current accessible cache.
  84.   
  85.   @param val: None indicating no caching is in effect. 
  86.     L{constants.CACHE_INTERFACES} indicating all interface query results are
  87.     cached. L{constants.CACHE_PROPERTIES} indicating all basic accessible
  88.     properties are cached plus all interfaces.
  89.   @type val: integer
  90.   '''
  91.     global _CACHE_LEVEL
  92.     if _CACHE_LEVEL != val:
  93.         _ACCESSIBLE_CACHE.clear()
  94.         if val == constants.CACHE_PROPERTIES:
  95.             r = registry.Registry()
  96.             r.registerEventListener(_updateCache, *constants.CACHE_EVENTS)
  97.         else:
  98.             r = registry.Registry()
  99.             r.deregisterEventListener(_updateCache, *constants.CACHE_EVENTS)
  100.     
  101.     _CACHE_LEVEL = val
  102.  
  103.  
  104. def clearCache():
  105.     '''Forces a clear of the entire cache.'''
  106.     _ACCESSIBLE_CACHE.clear()
  107.  
  108.  
  109. def printCache(template = '%s'):
  110.     '''
  111.   Prints the contents of the cache.
  112.   
  113.   @param template: Format string to use when printing
  114.   @type template: string
  115.   '''
  116.     print template % _ACCESSIBLE_CACHE
  117.  
  118.  
  119. def _updateCache(event):
  120.     '''
  121.   Invalidates an entry in the cache when the hash value of a source of an event
  122.   matches an entry in the cache.
  123.   
  124.   @param event: One of the L{constants.CACHE_EVENTS} event types
  125.   @type event: L{event.Event}
  126.   '''
  127.     
  128.     try:
  129.         _ACCESSIBLE_CACHE[hash(event.source)].wipe()
  130.     except KeyError:
  131.         return None
  132.  
  133.  
  134.  
  135. def _getAndCache(acc, value_name, get_method):
  136.     """
  137.   If property caching is enabled, use the cached proprty, or get the 
  138.   property and cache it. If property caching is disabled, simply get the 
  139.   property.
  140.  
  141.   @param value_name: The name of the value, like 'role' or 'description'.
  142.   @type value_name: string
  143.   @param get_method: Method used to get the property, should not have any 
  144.   arguments.
  145.   @type get_method: callable
  146.   @return: Value of property we are retrieving.
  147.   @rtype: object
  148.   """
  149.     if _CACHE_LEVEL != constants.CACHE_PROPERTIES:
  150.         return get_method()
  151.     cache = _ACCESSIBLE_CACHE
  152.     h = hash(acc)
  153.     
  154.     try:
  155.         pc = acc._property_cache
  156.     except AttributeError:
  157.         _CACHE_LEVEL != constants.CACHE_PROPERTIES
  158.         _CACHE_LEVEL != constants.CACHE_PROPERTIES
  159.         
  160.         try:
  161.             pc = cache[h]
  162.         except KeyError:
  163.             pc = _PropertyCache()
  164.             cache[h] = pc
  165.  
  166.         acc._property_cache = pc
  167.     except:
  168.         _CACHE_LEVEL != constants.CACHE_PROPERTIES
  169.  
  170.     
  171.     try:
  172.         value = getattr(pc, value_name)
  173.     except AttributeError:
  174.         _CACHE_LEVEL != constants.CACHE_PROPERTIES
  175.         _CACHE_LEVEL != constants.CACHE_PROPERTIES
  176.         value = get_method()
  177.         setattr(pc, value_name, value)
  178.     except:
  179.         _CACHE_LEVEL != constants.CACHE_PROPERTIES
  180.  
  181.     return value
  182.  
  183.  
  184. def _makeQuery(interface):
  185.     '''
  186.   Builds a function querying to a specific interface and returns it.
  187.   
  188.   @param interface: Class representing an AT-SPI interface
  189.   @type interface: class
  190.   @return: Function querying to the given interface
  191.   @rtype: function
  192.   '''
  193.     
  194.     def _inner(self):
  195.         '''
  196.     Queries an object for another interface.
  197.   
  198.     @return: An object with the desired interface
  199.     @rtype: object
  200.     @raise NotImplementedError: When the desired interface is not supported    
  201.     '''
  202.         iid = utils.getInterfaceIID(interface)
  203.         
  204.         try:
  205.             i = self._icache[iid]
  206.         except KeyError:
  207.             caching = True
  208.         except AttributeError:
  209.             caching = _CACHE_LEVEL is not None
  210.             if caching:
  211.                 self._icache = { }
  212.             
  213.         except:
  214.             caching
  215.  
  216.         if i is None:
  217.             raise NotImplementedError
  218.         i is None
  219.         return i
  220.         
  221.         try:
  222.             i = self.queryInterface(iid)
  223.             if i is not None:
  224.                 i = i._narrow(interface)
  225.         except Exception:
  226.             e = None
  227.             raise LookupError(e)
  228.  
  229.         if i is None:
  230.             if caching:
  231.                 self._icache[iid] = None
  232.             
  233.             raise NotImplementedError
  234.         i is None
  235.         if caching:
  236.             self._icache[iid] = i
  237.         
  238.         return i
  239.  
  240.     return _inner
  241.  
  242.  
  243. def _makeExceptionHandler(func):
  244.     '''
  245.   Builds a function calling the one it wraps in try/except statements catching
  246.   CORBA exceptions.
  247.   
  248.   @return: Function calling the method being wrapped
  249.   @rtype: function
  250.   '''
  251.     
  252.     def _inner(self, *args, **kwargs):
  253.         
  254.         try:
  255.             return func(self, *args, **kwargs)
  256.         except ORBit.CORBA.NO_IMPLEMENT:
  257.             e = None
  258.             raise NotImplementedError(e)
  259.         except ORBit.CORBA.Exception:
  260.             e = None
  261.             raise LookupError(e)
  262.  
  263.  
  264.     return _inner
  265.  
  266.  
  267. def _mixInterfaces(cls, interfaces):
  268.     '''
  269.   Add methods for querying to interfaces other than the base accessible to
  270.   the given class.
  271.   
  272.   @param cls: Class to mix interface methods into
  273.   @type cls: class
  274.   @param interfaces: Classes representing AT-SPI interfaces
  275.   @type interfaces: list of class
  276.   '''
  277.     for interface in interfaces:
  278.         name = 'query%s' % utils.getInterfaceName(interface)
  279.         func = _makeQuery(interface)
  280.         method = new.function(func.func_code, func.func_globals, name, func.func_defaults, func.func_closure)
  281.         setattr(cls, name, method)
  282.     
  283.  
  284.  
  285. def _mixExceptions(cls):
  286.     '''
  287.   Wraps all methods and properties in a class with handlers for CORBA 
  288.   exceptions.
  289.   
  290.   @param cls: Class to mix interface methods into
  291.   @type cls: class
  292.   '''
  293.     method_type = Accessibility.Accessible.getRole.__class__
  294.     for name in cls.__dict__.keys():
  295.         obj = cls.__dict__[name]
  296.         if name.startswith('_'):
  297.             continue
  298.             continue
  299.         if isinstance(obj, method_type):
  300.             method = _makeExceptionHandler(obj)
  301.             setattr(cls, name, method)
  302.             continue
  303.         if isinstance(obj, property):
  304.             if obj.fget:
  305.                 func = getattr(cls, obj.fget.__name__)
  306.                 getter = _makeExceptionHandler(func)
  307.             else:
  308.                 getter = None
  309.             if obj.fset:
  310.                 func = getattr(cls, obj.fset.__name__)
  311.                 setter = _makeExceptionHandler(func)
  312.             else:
  313.                 setter = None
  314.             setattr(cls, name, property(getter, setter))
  315.             continue
  316.     
  317.  
  318.  
  319. def _mixClass(cls, new_cls, ignore = []):
  320.     """
  321.   Adds the methods in new_cls to cls. After mixing, all instances of cls will
  322.   have the new methods. If there is a method name clash, the method already in
  323.   cls will be prefixed with '_mix_' before the new method of the same name is 
  324.   mixed in.
  325.   
  326.   @note: _ is not the prefix because if you wind up with __ in front of a 
  327.   variable, it becomes private and mangled when an instance is created. 
  328.   Difficult to invoke from the mixin class.
  329.  
  330.   @param cls: Existing class to mix features into
  331.   @type cls: class
  332.   @param new_cls: Class containing features to add
  333.   @type new_cls: class
  334.   @param ignore: Ignore these methods from the mixin
  335.   @type ignore: iterable
  336.   """
  337.     for name, func in new_cls.__dict__.items():
  338.         if name in ignore:
  339.             continue
  340.         
  341.         if isinstance(func, types.FunctionType):
  342.             method = new.function(func.func_code, func.func_globals, name, func.func_defaults, func.func_closure)
  343.             
  344.             try:
  345.                 old_method = getattr(cls, name)
  346.             except AttributeError:
  347.                 pass
  348.  
  349.             setattr(cls, '_mix_' + name, old_method)
  350.             setattr(cls, name, method)
  351.             continue
  352.         if isinstance(func, staticmethod):
  353.             
  354.             try:
  355.                 old_method = getattr(cls, name)
  356.             except AttributeError:
  357.                 pass
  358.  
  359.             setattr(cls, '_mix_' + name, old_method)
  360.             setattr(cls, name, func)
  361.             continue
  362.         if isinstance(func, property):
  363.             
  364.             try:
  365.                 old_prop = getattr(cls, name)
  366.             except AttributeError:
  367.                 pass
  368.  
  369.             setattr(cls, '_mix_' + name, old_prop)
  370.             setattr(cls, name, func)
  371.             continue
  372.     
  373.  
  374.  
  375. class _AccessibleMixin(object):
  376.     '''
  377.   Defines methods to be added to the Accessibility.Accessible class. The
  378.   features defined here will be added to the Accessible class at run time so
  379.   that all instances of Accessible have them (i.e. there is no need to
  380.   explicitly wrap an Accessible in this class or derive a new class from it.)
  381.   
  382.   @cvar SLOTTED_CLASSES: Mapping from raw Accessibility class to a new class
  383.     having the slots defined by L{SLOTS}
  384.   @type SLOTTED_CLASSES: dictionary
  385.   @cvar SLOTS: All slots to create
  386.   @type SLOTS: tuple
  387.   '''
  388.     SLOTTED_CLASSES = { }
  389.     SLOTS = ('_icache', '_property_cache', '_user_data')
  390.     
  391.     def __new__(cls):
  392.         """
  393.     Creates a new class mimicking the one requested, but with extra named 
  394.     defined in __slots__. The _cache attribute is used internally for interface
  395.     caching. The user_data field may be populated with whatever data structure
  396.     a client wishes to use. Neither is set to a default value by default.
  397.     
  398.     Note that we can't simply mix __slots__ into this class because __slots__
  399.     has an effect only at class creation time. 
  400.     
  401.     We also do not completely obliterate __slots__ to allow __dict__ to be
  402.     instantiated as normal as reducing the initialization and memory overhead
  403.     of the millions of accessible objects that are created is a good thing for
  404.     many clients.
  405.     
  406.     @param cls: Accessibility object class
  407.     @type cls: class
  408.     @return: Instance of the new class
  409.     @rtype: object
  410.     """
  411.         
  412.         try:
  413.             new_cls = _AccessibleMixin.SLOTTED_CLASSES[cls]
  414.         except KeyError:
  415.             new_cls = type(cls.__name__, (cls,), {
  416.                 '__module__': cls.__module__,
  417.                 '__slots__': _AccessibleMixin.SLOTS })
  418.             _AccessibleMixin.SLOTTED_CLASSES[cls] = new_cls
  419.  
  420.         obj = cls._mix___new__(new_cls)
  421.         return obj
  422.  
  423.     
  424.     def __del__(self):
  425.         """    
  426.     Decrements the reference count on the accessible object when there are no
  427.     Python references to this object. This provides automatic reference
  428.     counting for AT-SPI objects. Also removes this object from the cache if
  429.     we're caching properties. 
  430.     """
  431.         
  432.         try:
  433.             self.unref()
  434.         except Exception:
  435.             pass
  436.  
  437.  
  438.     
  439.     def __iter__(self):
  440.         '''
  441.     Iterator that yields one accessible child per iteration. If an exception is
  442.     encountered, None is yielded instead.
  443.     
  444.     @return: A child accessible
  445.     @rtype: Accessibility.Accessible
  446.     '''
  447.         for i in xrange(self.childCount):
  448.             
  449.             try:
  450.                 yield self.getChildAtIndex(i)
  451.             continue
  452.             except LookupError:
  453.                 yield None
  454.                 continue
  455.             
  456.  
  457.         
  458.  
  459.     
  460.     def __str__(self):
  461.         '''
  462.     Gets a human readable representation of the accessible.
  463.     
  464.     @return: Role and name information for the accessible
  465.     @rtype: string
  466.     '''
  467.         
  468.         try:
  469.             return '[%s | %s]' % (self.getRoleName(), self.name)
  470.         except Exception:
  471.             return '[DEAD]'
  472.  
  473.  
  474.     
  475.     def __nonzero__(self):
  476.         '''
  477.     @return: True, always
  478.     @rtype: boolean
  479.     '''
  480.         return True
  481.  
  482.     
  483.     def __getitem__(self, index):
  484.         '''
  485.     Thin wrapper around getChildAtIndex.
  486.     
  487.     @param index: Index of desired child
  488.     @type index: integer
  489.     @return: Accessible child
  490.     @rtype: Accessibility.Accessible
  491.     '''
  492.         n = self.childCount
  493.         if index >= n:
  494.             raise IndexError
  495.         index >= n
  496.         if index < -n:
  497.             raise IndexError
  498.         index < -n
  499.         if index < 0:
  500.             index += n
  501.         
  502.         return self.getChildAtIndex(index)
  503.  
  504.     
  505.     def __len__(self):
  506.         '''
  507.     Thin wrapper around childCount.
  508.     
  509.     @return: Number of child accessibles
  510.     @rtype: integer
  511.     '''
  512.         return self.childCount
  513.  
  514.     
  515.     def _get_user_data(self):
  516.         '''
  517.     Get user_data from global dictionay fo this accessible.
  518.  
  519.     @return: Any data the user assigned, or None.
  520.     @rtype: object
  521.     '''
  522.         h = hash(self)
  523.         
  524.         try:
  525.             ud = self._user_data
  526.         except AttributeError:
  527.             
  528.             try:
  529.                 ud = _ACCESSIBLE_USER_DATA[h]
  530.             except KeyError:
  531.                 ud = _UserData()
  532.                 _ACCESSIBLE_USER_DATA[h] = ud
  533.             except:
  534.                 None<EXCEPTION MATCH>KeyError
  535.             
  536.  
  537.             None<EXCEPTION MATCH>KeyError
  538.  
  539.         self._user_data = ud
  540.         return ud.value
  541.  
  542.     
  543.     def _set_user_data(self, value):
  544.         '''
  545.     Set arbitrary data to user_data.
  546.  
  547.     @param value: Value to set in user_data
  548.     @type value: object
  549.     '''
  550.         h = hash(self)
  551.         
  552.         try:
  553.             ud = self._user_data
  554.         except AttributeError:
  555.             
  556.             try:
  557.                 ud = _ACCESSIBLE_USER_DATA[h]
  558.             except KeyError:
  559.                 ud = _UserData()
  560.                 _ACCESSIBLE_USER_DATA[h] = ud
  561.             except:
  562.                 None<EXCEPTION MATCH>KeyError
  563.             
  564.  
  565.             None<EXCEPTION MATCH>KeyError
  566.  
  567.         self._user_data = ud
  568.         ud.value = value
  569.  
  570.     user_data = property(_get_user_data, _set_user_data)
  571.     
  572.     def _get_name(self):
  573.         '''
  574.     Gets the name of the accessible from the cache if it is available, 
  575.     otherwise, fetches it remotely.
  576.     
  577.     @return: Name of the accessible
  578.     @rtype: string
  579.     '''
  580.         return _getAndCache(self, 'name', self._get_name)
  581.  
  582.     name = property(_get_name, Accessibility.Accessible._set_name)
  583.     
  584.     def _get_parent(self):
  585.         '''
  586.     Gets the parent of the accessible from the cache if it is available, 
  587.     otherwise, fetches it remotely.
  588.     
  589.     @return: Parent of the accessible
  590.     @rtype: Accessibility.Accessible
  591.     '''
  592.         return _getAndCache(self, 'parent', self._get_parent)
  593.  
  594.     parent = property(_get_parent)
  595.     
  596.     def getRoleName(self):
  597.         '''
  598.     Gets the unlocalized role name of the accessible from the cache if it is 
  599.     available, otherwise, fetches it remotely.
  600.     
  601.     @return: Role name of the accessible
  602.     @rtype: string
  603.     '''
  604.         return _getAndCache(self, 'rolename', self._mix_getRoleName)
  605.  
  606.     
  607.     def getRole(self):
  608.         '''
  609.     Gets the role of the accessible from the cache if it is 
  610.     available, otherwise, fetches it remotely.
  611.     
  612.     @return: Role of the accessible
  613.     @rtype: Accessibility.Role
  614.     '''
  615.         return _getAndCache(self, 'role', self._mix_getRole)
  616.  
  617.     
  618.     def _get_description(self):
  619.         '''    
  620.     Gets the description of the accessible from the cache if it is available,
  621.     otherwise, fetches it remotely.
  622.     
  623.     @return: Description of the accessible
  624.     @rtype: string
  625.     '''
  626.         return _getAndCache(self, 'description', self._get_description)
  627.  
  628.     description = property(_get_description, Accessibility.Accessible._set_description)
  629.     
  630.     def getIndexInParent(self):
  631.         """
  632.     Gets the index of this accessible in its parent. Uses the implementation of
  633.     this method provided by the Accessibility.Accessible object, but checks the
  634.     bound of the value to ensure it is not outside the range of childCount 
  635.     reported by this accessible's parent.
  636.     
  637.     @return: Index of this accessible in its parent
  638.     @rtype: integer
  639.     """
  640.         i = self._mix_getIndexInParent()
  641.         
  642.         try:
  643.             return min(self.parent.childCount - 1, i)
  644.         except AttributeError:
  645.             return -1
  646.  
  647.  
  648.     
  649.     def getApplication(self):
  650.         '''
  651.     Gets the most-parent accessible (the application) of this
  652.     accessible. Tries using the getApplication method introduced in
  653.     AT-SPI 1.7.0 first before resorting to traversing parent links.
  654.     
  655.     @warning: Cycles involving more than the previously traversed accessible 
  656.       are not detected by this code.
  657.     @return: Application object
  658.     @rtype: Accessibility.Application
  659.     '''
  660.         
  661.         try:
  662.             app = self._mix_getApplication()
  663.         except AttributeError:
  664.             app = None
  665.  
  666.         if app:
  667.             return app
  668.         curr = self
  669.         
  670.         try:
  671.             while curr.parent is not None and not (curr.parent == curr):
  672.                 curr = curr.parent
  673.                 continue
  674.                 app
  675.             curr.ref()
  676.             return curr._narrow(Accessibility.Application)
  677.         except:
  678.             app
  679.             return None
  680.  
  681.  
  682.  
  683.  
  684. class _RelationMixin(object):
  685.     """
  686.   Defines methods to be added to the Relation class. At this time it only
  687.   overrides L{_RelationMixin.getTarget} which by the IDL's standard is
  688.   supposed to return CORBA.Objects but we expect LAccessibility.Accessible
  689.   objects (see http://bugzilla.gnome.org/show_bug.cgi?id=435833). 
  690.   This seems to be a problem especially with the Java implementation of CORBA.
  691.   """
  692.     
  693.     def getTarget(self, index):
  694.         """
  695.     Overrides the regular getTarget to return Accessibility.Accessible
  696.     objects.
  697.  
  698.     @return: The 'nth' target of this Relation.
  699.     @rtype: Accessibility.Accessible
  700.     """
  701.         target = self._mix_getTarget(index)
  702.         if not isinstance(target, Accessibility.Accessible):
  703.             target = target._narrow(Accessibility.Accessible)
  704.         
  705.         target.ref()
  706.         return target
  707.  
  708.  
  709.  
  710. class _UnrefMixin(object):
  711.     '''
  712.   This mixin addresses the issue we have with unreferencing non-primitives.
  713.   '''
  714.     
  715.     def __del__(self):
  716.         '''
  717.     Unrefence the instance when Python GCs it. Why do we need this twice?
  718.     '''
  719.         
  720.         try:
  721.             self.unref()
  722.         except Exception:
  723.             pass
  724.  
  725.  
  726.  
  727. map(_mixExceptions, constants.ALL_INTERFACES)
  728. map(_mixExceptions, [
  729.     Accessibility.StateSet])
  730. _mixClass(Accessibility.Accessible, _AccessibleMixin, [
  731.     '_get_name',
  732.     '_get_description',
  733.     '_get_parent'])
  734. _mixInterfaces(Accessibility.Accessible, constants.ALL_INTERFACES)
  735. _mixClass(Accessibility.Relation, _RelationMixin)
  736. map((lambda cls: _mixClass(cls, _UnrefMixin)), (Accessibility.StateSet, Accessibility.Relation))
  737.